/*	xrc.h
*/

#ifndef	__xrc_h__
#define	__xrc_h__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
//#include <conio.h>
#include <ctype.h>
#include <math.h>
#include "sub.h"

#if defined(WIN32)
#define int64 __int64
#else
#define int64 long long
#endif

#define HASINIT	 0x39A8C24F
#define INT32MAX 2147483647
#define TOKEN_STACK_SIZE	128

/*token_type*/
enum tok_types{ DELIMITER = 1, IDENTIFIER, KEYWORD, TEMP, STRING, CHARACTOR, NUMBER, TYPE, BLOCK, PRECOMPILE };

enum ops{
//  <       <=  >   >=  ==  !=  &&  ||  &   |   ^   <<  >>    ++, --, +=, -=, *=, /=, %=, ^=  ~=    [    ]    .    ->   
	LT = 2, LE, GT, GE, EQ, NE, AA, OO, AI, OI, XI, SL, SR,   AD, DE, AQ, DQ, MQ, VQ, OQ, RQ, NQ,   ALY, ARY, FLT, PTR, 
//  +  -  *  /  %  =     <=>   <=>
	A, D, M, V, O, ASMT, INIT, INIS,
//  je  jne  jmp
    JE, JNE, JMP,
//  case  size  ++   --   ++   --   &        *       +   -   ~    !   	
	CAST, SIZE, LAD, LDE, RAD, RDE, ADDRESS, UNADDR, ZZ, FF, REV, UN,  
//  ?: 
	COND,

	EXPEND,
	PUSH, POP, RET, CALL, PUSHEIP, POPEIP, BEG,
	CPUSH, CCALL, CBEG,
};

static char g_oprname[64][12] = {  
	"LAB", "G",
	"<", "<=", ">", ">=", "==", "!=", "&&", "||", "&", "|", "^", "<<", ">>", "++", "--", "+=", "-=", "*=", "/=", "%=", "^=", "~=", "[]", "[]", ".", "->",
	"+", "-", "*", "/", "%", "=", "INIT", "INIS", 
	"JE", "JNE", "JMP",
	"cast", "size", "++", "--", "++", "--", "&", "*", "+", "-", "~ ", "!",
	"?:", 
	"EXPEND",
	"PUSH", "POP", "RET", "CALL", "PUSHEIP", "POPEIP", "BEG",
	"CPUSH", "CCALL", "CBEG",
};

#define OPR_NUM( opr ) ( (opr)>=LT && (opr)<=JMP ? 2 : ( (opr)==COND ? 3 : 1 ) )

/*key works*/
enum key_enum{
	K_NULL,
	DEFINE, TYPEDEF,
	AUTO, REGISTER, STATIC, EXTERN, 
	CONSTT, VOLATILE, CONST, VOID, CHAR, SIGNED, UNSIGNED, SHORT,
	INT, LONG, FLOAT, DOUBLE, STRUCT, UNION, ENUM, TYPENAME,
	IF, ELSE, FOR, DO, WHILE, SWITCH, CASE, BREAK, CONTINUE, DEFAULT, GOTO,
	SIZEOF,RETURN,
	FINISHED, END, NOP
};

/*base type*/
enum type_enum{	
	T_NULL,
	T_FUNCTION, T_POINTER, T_ARRAY, T_STRUCT, T_UNION, T_ENUM,
	T_CHAR, T_UCHAR, T_SHORT, T_USHORT, T_INT, T_UINT, T_LONG, T_ULONG, T_VOID, 
	T_LONG_LONG, T_ULONG_LONG, T_FLOAT, T_DOUBLE, T_LONG_DOUBLE, 
	S_VALUE, S_STRUCT_TAG, S_UNION_TAG, S_FIELD_TAG, S_ENUM_TAG, S_STRING, S_TEXT,	/*other symbol types*/
};

static char g_typename[64][12] = {	
	"NULL",
	"FUNCTION", "POINTER", "ARRAY", "STRUCT", "UNION", "ENUM",
	"CHAR", "UCHAR", "SHORT", "USHORT", "INT", "UINT", "LONG", "ULONG", "VOID", 
	"LONG_LONG", "ULONG_LONG", "FLOAT", "DOUBLE", "LONG_DOUBLE", 
	"VALUE", "STRUCT_TAG", "UNION_TAG", "FIELD_TAG", "ENUM_TAG", "STRING", "TEXT",	/*other symbol types*/
};

/*symbol*/
typedef struct _symbol tsymbol_t;
typedef struct _symbol * psymbol_t;
struct _symbol{
	int mty; 
	int len;
	char * data; 
	psymbol_t next;
};


/*type*/
typedef struct type_t ttype_t;	
typedef struct type_t *	ptype_t;
typedef struct type_list_t ttype_list_t;
typedef struct type_list_t * ptype_list_t;
struct type_t{
	int bty;
	int size;
	ptype_t	ty;
	ptype_list_t sty;
	char * name;
	char * tag;
	char * pos;
};
struct type_list_t{
	ptype_t ty;
	ptype_list_t next;
};


/*var*/
typedef struct var_t v_t;
typedef struct var_t * pv_t;
struct var_t{
	int v_tmp;
	char v_field;
	char * v_name;
	int64  v_valb;
	double v_vald;
	ptype_t v_type;

	char *begin;
	char *end;
	char *pos;
	
	char gad;
	char used;
	int  offset;
};


/*exp*/
typedef struct _exp exp_t;
typedef struct _exp * pexp_t;
struct _exp{
	char opr;
	int lab;
	v_t var;
};


/*code*/
typedef struct _code code_t;
typedef struct _code * pcode_t;
struct _code{
	char opr;
	struct{
		int  i, n, t;
	}lab;
	v_t var[3];
	code_t * next; 
};


/*cmd list*/
typedef struct _cmd{
	char cmd;
	struct{
		char type;
		int  size;
		union{
			int64 i;
			double d;
		}d;
	}d[3];
	int ex;
	int inioffs;
	int initype;
	struct _cmd * next;
	struct _cmd * pre;
}cmd_t;


/*function*/
typedef struct _function fun_t;
typedef struct _function * pfun_t;
struct _function{
	int argnum;
	char * name;
	ttype_t * ty;
	stack_t vartable;
	code_t * clist;

	int ret;
	int bas;
	int top;
	cmd_t * cmdlist;
};

/*typedef*/
typedef struct _typedef_node{
	char	*ty_name;
	ptype_t ty;
}typedef_node_t;

/*enum*/
typedef struct _enum_node{
	char	*ty_name;
	int     value;
}enum_node_t;


/*token*/
typedef struct token_node
{
	char *token;
	char token_type;
	char tok;
	ptype_t ty;
}token_t;

/*base type*/
typedef struct base_type{
	int cls, cons, sign, size, type, vol;
	char * pos;
	ptype_t ty;
}basety_t;

/*xrc stack*/
typedef struct _xrc_stack{
	int	top;
	int	size;
	char * s;
}rsk_t;



/*global struct*/
typedef struct _xrc_ctx{
	//error
	char error_info[512];
	//run
	int	clev;
	int sksize;
	char * glb;
	char * esp;
	cmd_t * eip;
	fun_t runfun;
	stack_t runfunstk;
	rsk_t runsk;
	pool_t * mempool;
	//lex
	char * source;
	char * prog;	
	char * preg;
	char * token;
	char * tostr;
	char token_type;
	char tok;
	int lineno;
	int tokenlen;	
	int64 tok_oi;	/* token_type == NUMBER, real value saved in oi/od */
	double tok_od;
	ptype_t number_type;
	//dcl
	int tok_top;
	token_t tok_stack[TOKEN_STACK_SIZE];
	basety_t sbt;
	ttype_t base_ty;
	ptype_t pbase_ty;
	//exp
	int exp_cnt;
	int exp_tmp;
	stack_t stack_exp;
	//par
	int		glab;
	fun_t * cur_pfun;
	stack_t typedef_stack;
	stack_t enum_stack;
	stack_t fun_stack;
	fun_t	global_fun;
	int		offset;
	v_t		initvar;
	//tye
	ttype_list_t ttype_list;
	ptype_list_t ptype_list;
	psymbol_t sym_list;
	//lib
	hh_hash_t * phash;
	stack_t callctx_stk;
	//interface
	int binit;
	int jmpidx;
	jmp_buf parjmp;
	jmp_buf exejmp;
}xrc_t, *xrc_p;

extern ttype_t	type_char;
extern ttype_t	type_double;
extern ttype_t	type_float;
extern ttype_t	type_int;
extern ttype_t	type_long_double;
extern ttype_t	type_long_long;
extern ttype_t  type_short;
extern ttype_t  type_long;
extern ttype_t	type_uchar;
extern ttype_t	type_ulong;
extern ttype_t	type_ulong_long;
extern ttype_t	type_uint;
extern ttype_t	type_ushort;
extern ttype_t	type_void;
extern ttype_t  type_pointer;
extern ttype_t	type_function;


void sntx_err( xrc_p xrc, char * error, ... );
void sntx_type_err( xrc_p xrc, ptype_t ty1, ptype_t ty2, int opr );

int get_token( xrc_p xrc );
void put_back( xrc_p xrc );
int sort_enum_name( xrc_p xrc, char * name, int *value );
ptype_t sort_type_name( xrc_p xrc, char * name );

ptype_t ty_new_type( xrc_p xrc );
ptype_t ty_add_node( xrc_p xrc, ptype_t head, ttype_t ty );
ptype_t ty_free_type( xrc_p xrc, ptype_t head );
ptype_t ty_dump_type( xrc_p xrc, ptype_t ty );
ptype_list_t tyl_dump( xrc_p xrc, ptype_list_t tyl );
ptype_list_t tyl_new_list( xrc_p xrc );
ptype_list_t tyl_sort_node( xrc_p xrc, ptype_list_t tyl, char *tag, int mty );
ptype_list_t tyl_add_node( xrc_p xrc, ptype_list_t tyl, ptype_t ty, int check );	//check - is check exist
ptype_list_t tyl_free( xrc_p xrc, ptype_list_t tyl );
ptype_list_t tyl_init( xrc_p xrc );

psymbol_t sym_new_list( xrc_p xrc );
psymbol_t sym_sort_node( xrc_p xrc, psymbol_t slt, char * tag, int mty );
psymbol_t sym_add_node( xrc_p xrc, psymbol_t slt, tsymbol_t sym );
psymbol_t sym_new_node( xrc_p xrc, psymbol_t slt, int mty, char *string, int len, ptype_t ty );
psymbol_t sym_del_node( xrc_p xrc, psymbol_t slt, psymbol_t dst );
psymbol_t sym_free( xrc_p xrc, psymbol_t slt );
psymbol_t sym_init( xrc_p xrc );

int is_dclbegin( xrc_p xrc,int tok);
ptype_t dclthis( xrc_p xrc, char **name );
ptype_t dclex( xrc_p xrc, char **name, ptype_t *basety );

int is_unsigned( xrc_p xrc, ptype_t ty );
int is_basetype( xrc_p xrc, ptype_t ty1 );
int is_equtype( xrc_p xrc, ptype_t ty1, ptype_t ty2 );
int is_cmptype( xrc_p xrc, ptype_t ty1, ptype_t ty2 );
int type_size( xrc_p xrc, ptype_t ty );
int tyl_size( xrc_p xrc, ptype_list_t tyl );
int type_left_size( xrc_p xrc, ptype_t ty, int left );
int type_field_offset( xrc_p xrc, ptype_t ty, char * field );
int type_field_num( xrc_p xrc, ptype_t ty );

code_t * code_list( xrc_p xrc );
code_t * code_list_free( xrc_p xrc, code_t * clist );
code_t * code_insert( xrc_p xrc, code_t * list, code_t code );
code_t * code_connect( xrc_p xrc, code_t * first, code_t * second );

cmd_t * cmd_list( xrc_p xrc );
cmd_t * cmd_list_free( xrc_p xrc, cmd_t * cmdlt );
cmd_t * cmd_insert( xrc_p xrc, cmd_t * list, cmd_t cmd );
cmd_t * cmd_connect( xrc_p xrc, cmd_t * first, cmd_t * second );

int par_num( xrc_p xrc, v_t * val, char *token );
int par_args( xrc_p xrc, fun_t * fun );

code_t * exp_callback( xrc_p xrc, void (*expf)(xrc_p), code_t * clist );
code_t * exp_callback_init( xrc_p xrc, void (*expf)(xrc_p), code_t * clist );
int exp_constint( xrc_p xrc );
void exp_expression( xrc_p xrc );
void exp_mayempty_forexp( xrc_p xrc );
void exp_assignment( xrc_p xrc );
void exp_conditional( xrc_p xrc );
void exp_logic_or( xrc_p xrc );
void exp_logic_and( xrc_p xrc );
void exp_inclusive_or( xrc_p xrc );
void exp_exclusive_or( xrc_p xrc );
void exp_and( xrc_p xrc );
void exp_equality( xrc_p xrc );
void exp_relational( xrc_p xrc );
void exp_shift( xrc_p xrc );
void exp_additive( xrc_p xrc );
void exp_multiplicative( xrc_p xrc );
void exp_cast( xrc_p xrc );
void exp_unary( xrc_p xrc );
void exp_postfix( xrc_p xrc );
void atomic( xrc_p xrc );
void exp_show_code( xrc_p xrc, code_t * clist );

void gen_lab( xrc_p xrc, code_t * lab );
void expect( xrc_p xrc, char ch );
void gen_lab( xrc_p xrc, code_t * lab );
code_t * stmt_jump( xrc_p xrc, code_t * clist, int lab, char opr, int num );
code_t * stmt( xrc_p xrc, code_t * clist, code_t * lablist, int bk_lab, int cn_lab, int level );

void stk_init( xrc_p xrc );
void stk_free( xrc_p xrc );
code_t * decl_global( xrc_p xrc, stack_t * varstack, code_t * tail, ptype_t * ret_ty );
code_t * decl_local( xrc_p xrc, stack_t * varstack, code_t * last );
int par_function( xrc_p xrc, fun_t * fun );
code_t * initialize_var( xrc_p xrc, v_t *var, code_t * tail, int *num );

void fun_set( xrc_p xrc, fun_t * fun );
void push_funs( xrc_p xrc, fun_t fun );
void var_init( v_t * var );

void cmd_function( xrc_p xrc, fun_t * fun );
void run_go( xrc_p xrc, cmd_t * cmdlist, int funidx );
void run_init( xrc_p xrc, int sksize );
void run_free( xrc_p xrc );

int is_basetype( xrc_p xrc, ptype_t ty );
int is_ztype( xrc_p xrc, ptype_t ty );
int is_ftype( xrc_p xrc, ptype_t ty );
int is_equtype( xrc_p xrc, ptype_t ty1, ptype_t ty2 );
int type_size( xrc_p xrc, ptype_t ty );
int type_string( xrc_p xrc, ptype_t ty, char * str, int maxsize );

#define OPERATOR( c )		( xrc->token_type != DELIMITER ? 0 : ((c == *xrc->token)?*xrc->token:0) )
#define is_white( c )		( ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n' ) ? 1 : 0 )
#define is_alpha( c )		( ((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z') ) ? 1 : 0 )
#define is_delim( c )		( ( strchr(" !;,+-<>'/*%^=()[]{}:.&|@#$\\\"\'?", (c) ) || (c) == 9 || (c) == '\r' || (c) == 0 ) ? 1 : 0 )
#define is_hex( c )			( ( (c)>='0'&&(c)<='9' ) ? (c)-'0' : ( ( (c)>='a'&&(c)<='z' ) ? c-'a'+10 : ( ( (c)>='A'&&(c)<='Z' ) ? (c)-'A'+10 : -1 ) ) )

#define make_token( size )	(char*)pool_malloc( xrc->mempool, size, "make_token" )
#define make_tostr( size )	(char*)pool_malloc( xrc->mempool, size, "make_token" )
#define free_token()		{							\
		if( xrc->token )	pool_free( xrc->mempool, xrc->token );	\
		if( xrc->tostr )	pool_free( xrc->mempool, xrc->tostr );	\
	}

#define type_atom_szie( ty ) ( ( type_size(xrc,ty)<=4?4:type_size(xrc,ty) ) + 4 )
#define num_atom_szie( num ) ( (num<=4?4:num) + 4 )



//////////////////////////////////////////////////////////////////////////////////

typedef struct _regfunc{
	char * fname;
	void * fptrs;
	char   bdouble;
}regfunc_t;

typedef struct { int arg[   32]; } libargs_00032_t; typedef int (*libfunc_00032_t)(libargs_00032_t a);
typedef struct { int arg[   64]; } libargs_00064_t; typedef int (*libfunc_00064_t)(libargs_00064_t a);
typedef struct { int arg[  128]; } libargs_00128_t; typedef int (*libfunc_00128_t)(libargs_00128_t a);
typedef struct { int arg[  256]; } libargs_00256_t; typedef int (*libfunc_00256_t)(libargs_00256_t a);
typedef struct { int arg[  512]; } libargs_00512_t; typedef int (*libfunc_00512_t)(libargs_00512_t a);
typedef struct { int arg[ 1024]; } libargs_01024_t; typedef int (*libfunc_01024_t)(libargs_01024_t a);
typedef struct { int arg[ 2048]; } libargs_02048_t; typedef int (*libfunc_02048_t)(libargs_02048_t a);
typedef struct { int arg[ 4096]; } libargs_04096_t; typedef int (*libfunc_04096_t)(libargs_04096_t a);
typedef struct { int arg[ 8192]; } libargs_08192_t; typedef int (*libfunc_08192_t)(libargs_08192_t a);
typedef struct { int arg[16384]; } libargs_16384_t; typedef int (*libfunc_16384_t)(libargs_16384_t a);


typedef struct _callctx{
	int asm_idx;
	int64 asm_argtab[100];
	int asm_argtye[100];
}callctx_t;

int lib_init( xrc_p xrc );
int lib_free( xrc_p xrc );
int lib_check( xrc_p xrc, char *s, char **ptr );

void ccall_ctx( xrc_p xrc, int bpush );
void ccall_push( xrc_p xrc, int64 i, double d, int argtype );
int  ccall_call( xrc_p xrc, void * funptr );

void ccall_lock();
void ccall_unlock();

#endif

